﻿using System;
using Glue;
using Xunit;

namespace GlueExamples
{
    namespace StrictAndAutomagicalModes
    {
public class DomainPerson
{
    public String Name { get; set; }
    public DomainAddress Address { get; set; }
}

public class DomainAddress
{
    public String StreetAddress { get; set; }
}

public class GuiPerson
{
    public String Name { get; set; }
    public GuiAddress Address { get; set; }
}

public class GuiAddress
{
    public String StreetAddress { get; set; }
}

        public class GuiPersonWithConstructor
        {
            public GuiPersonWithConstructor(String name)
            {
                Name = name;
            }

            public String Name { get; set; }
            public GuiAddress Address { get; set; }
        }

        public class When_in_StrictMode
        {
            private readonly Mapping<DomainPerson, GuiPerson> mapping;
            private readonly DomainPerson domainPerson;

            public When_in_StrictMode()
            {
                mapping = new Mapping<DomainPerson, GuiPerson>();
                mapping.Relate(x => x.Name, y => y.Name);
                mapping.Relate(x => x.Address.StreetAddress, y => y.Address.StreetAddress);
                
                domainPerson = new DomainPerson
                {
                    Name = "Tore",
                    Address = new DomainAddress { StreetAddress = "the street address" }
                };
            }

            [Fact]
            public void Should_map_when_toObject_is_instantiated()
            {
                var guiPerson = new GuiPerson {Address = new GuiAddress()};
                mapping.Map(domainPerson, guiPerson);
                Assert.Equal(domainPerson.Name, guiPerson.Name);
                Assert.Equal(domainPerson.Address.StreetAddress, guiPerson.Address.StreetAddress);
            }

            [Fact]
            public void Should_not_accept_null_as_toObject()
            {
                Assert.Throws(typeof(GlueException), ()=> mapping.Map(domainPerson,null));
            }

            [Fact]
            public void Should_not_accept_uninstantiated_nested_object()
            {
                var guiPerson = new GuiPerson {Address = null};
                Assert.Throws(typeof(GlueException), ()=> mapping.Map(domainPerson, guiPerson));
            }
        }

        public class When_in_Automagical_mode
        {
            private readonly Mapping<DomainPerson, GuiPerson> mapping;
            private readonly DomainPerson domainPerson;
            private readonly Mapping<DomainPerson, GuiPersonWithConstructor> complexMapping;

            public When_in_Automagical_mode()
            {
                mapping = new Mapping<DomainPerson, GuiPerson>();
                mapping.Relate(x => x.Name, y => y.Name);
                mapping.Relate(x => x.Address.StreetAddress, y => y.Address.StreetAddress);

                complexMapping = new Mapping<DomainPerson, GuiPersonWithConstructor>();
                complexMapping.Relate(x => x.Name, y => y.Name);
                complexMapping.Relate(x => x.Address.StreetAddress, y => y.Address.StreetAddress);

                domainPerson = new DomainPerson
                {
                    Name = "Tore",
                    Address = new DomainAddress { StreetAddress = "the street address" }
                };
            }

            [Fact]
            public void Should_create_toObject_on_the_fly()
            {
                var guiPerson =mapping.Map(domainPerson);
                Assert.Equal(domainPerson.Name,guiPerson.Name);
                Assert.Equal(domainPerson.Address.StreetAddress, guiPerson.Address.StreetAddress);
            }

            [Fact]
            public void Should_create_nested_toObject_on_the_fly()
            {
                var guiPerson = mapping.Map(domainPerson);
                Assert.Equal(domainPerson.Name, guiPerson.Name);
                Assert.Equal(domainPerson.Address.StreetAddress, guiPerson.Address.StreetAddress);
            }

            [Fact]
            public void Will_fail_if_no_parameterless_constructor_or_creator_exists()
            {
                Assert.Throws(typeof(GlueException), ()=> complexMapping.Map(domainPerson));
            }

            [Fact]
            public void Should_create_toObject_with_constructor_when_creator_exists()
            {
                complexMapping.AddCreator(typeof(GuiPersonWithConstructor), x => new GuiPersonWithConstructor(""));
                var guiPerson = complexMapping.Map(domainPerson);
                Assert.Equal(domainPerson.Name, guiPerson.Name);
                Assert.Equal(domainPerson.Address.StreetAddress, guiPerson.Address.StreetAddress);
            }
        }
    }
}
